package copyengine.ui.component.scrollablePanel.common.moveOperator
{
    import com.greensock.TweenMax;
    import com.greensock.easing.Cubic;

    import copyengine.log.CELog;
    import copyengine.ui.component.scrollablePanel.scrollPanel.CEScrollPanel;
    import copyengine.ui.touch.CETouchProxy;
    import copyengine.utils.CEConst;
    import copyengine.utils.GeneralUtils;

    import flash.utils.getTimer;

    import starling.display.DisplayObject;
    import starling.events.Touch;

    /**
     *  处理滚动式Touch事件的响应操作, 模拟现实手机上的List实现效果 按住滑动 Slide时候滑动一段距离
     */
    public class CEScrollableMoveOperator
    {

        /**
         *如果Touch的时间(TouchDown 和 TouchUp之间的间隔) 小于该值 则认为应该滑动
         */
        public static const TOUCH_CONFIRM_SCROLL_TIME:int = 300;

        private var mScrollPanel:CEScrollPanel;

        function CEScrollableMoveOperator()
        {
        }

        public function initialize(_scrollPanel:CEScrollPanel, _isLockInView:Boolean):void
        {
            mScrollPanel = _scrollPanel;
            mIsLockInView = _isLockInView;
            //注意!! Click事件也是点击Up事件
            mTouchProxy = new CETouchProxy(mScrollPanel.container,
                                           onTouchUp, onTouchDown, onTouchUp, onTouchMove)
        }

        public function dispose():void
        {
            mTouchProxy.dispose();
            mTouchProxy = null;
        }

        //======================//
        //== Touch 相关
        //======================//

        /**
         * 记录Touch事件开始后的Pos点
         */
        private var mTouchDownPosX:int;
        private var mTouchDownPosY:int;

        /**
         * Move时候用于缓存上次Move的距离
         */
        private var mMoveLastCheckPosX:int;
        private var mMoveLastCheckPosY:int;

        /**
         * 开始Touch事件的时间，用于计算
         */
        private var mTouchStartTime:int;
        private var mTouchProxy:CETouchProxy;


        private function onTouchDown(_targetMc:DisplayObject, _touch:Touch):void
        {
            mTouchStartTime = getTimer();
            mTouchDownPosX = mMoveLastCheckPosX = _touch.globalX;
            mTouchDownPosY = mMoveLastCheckPosY = _touch.globalY;
            startMoveScrollPanel();
        }

        private function onTouchUp(_targetMc:DisplayObject, _touch:Touch):void
        {
            var currentCheckPosX:int = _touch.globalX;
            var moveOffsetFromBeginX:int = currentCheckPosX - mTouchDownPosX;
            var currentCheckPosY:int = _touch.globalY;
            var moveOffsetFromBeginY:int = currentCheckPosY - mTouchDownPosY;
            moveScrollPanelOnTouchCancel(getTimer() - mTouchStartTime, moveOffsetFromBeginX, moveOffsetFromBeginY);
        }

        private function onTouchMove(_targetMc:DisplayObject, _touch:Touch):void
        {
            var moveOffsetPosX:int = _touch.globalX - mMoveLastCheckPosX;
            var moveOffsetPosY:int = _touch.globalY - mMoveLastCheckPosY;
            mMoveLastCheckPosX = _touch.globalX;
            mMoveLastCheckPosY = _touch.globalY;
            moveScrollPanelDuringTouch(moveOffsetPosX, moveOffsetPosY)
        }

        //===========================//
        //== 移动相关
        //===========================//

        private var mIsLockInView:Boolean;
        private var mCurrentTween:TweenMax;

        private function startMoveScrollPanel():void
        {
            mCurrentTween && mCurrentTween.kill();
            mCurrentTween = null;
        }

        public function moveScrollPanelDuringTouch(_moveOffsetX:int, _moveOffsetY:int):void
        {
            var newViewportPosX:Number = 0;
            var newViewportPosY:Number = 0;
            if (mScrollPanel.direction == CEConst.DIR_HORIZONTAL) {
                newViewportPosX = doMoveScrollPanelXDirection(_moveOffsetX);
                newViewportPosY = mScrollPanel.viewportRect.y;
            } else if (mScrollPanel.direction == CEConst.DIR_VERTICAL) {
                newViewportPosX = mScrollPanel.viewportRect.x;
                newViewportPosY = doMoveScrollPanelYDirection(_moveOffsetY);
            } else {
                CELog.err("CEScrollableMoveOperator->unknown scrollPanel direction : " + mScrollPanel.direction);
            }
            mScrollPanel.moveViewPort(newViewportPosX, newViewportPosY);
        }

        public var mScrollTweenPosX:int;
        public var mScrollTweenPosY:int;

        public function moveScrollPanelOnTouchCancel(_duringTime:Number, _duringTouchMoveOffsetX:int, _duringTouchMoveOffsetY:int):void
        {
            var scrollToPositionX:int;
            var scrollToPositionY:int;

            if (mScrollPanel.direction == CEConst.DIR_HORIZONTAL) {
                scrollToPositionX = calculateCancelScrollToPositionX(_duringTouchMoveOffsetX, _duringTime);
                scrollToPositionY = mScrollPanel.viewportRect.y;
            } else {
                scrollToPositionX = mScrollPanel.viewportRect.x;
                scrollToPositionY = calculateCancelScrollToPositionY(_duringTouchMoveOffsetY, _duringTime);
            }

            if (mScrollPanel.viewportRect.x != scrollToPositionX || mScrollPanel.viewportRect.y != scrollToPositionY) {
                mScrollTweenPosX = mScrollPanel.viewportRect.x;
                mScrollTweenPosY = mScrollPanel.viewportRect.y;
                mCurrentTween = TweenMax.to(this, 0.7, {
                    mScrollTweenPosX: scrollToPositionX,
                    mScrollTweenPosY: scrollToPositionY,
                    onUpdate: onScrollTweenUpdate,
                    onComplete: onScrollTweenComplete,
                    ease: Cubic.easeOut
                });
            }
        }

        private function onScrollTweenUpdate():void {mScrollPanel.moveViewPort(mScrollTweenPosX, mScrollTweenPosY);}

        private function onScrollTweenComplete():void {mCurrentTween = null;}


        //========================//
        //==Private  Function
        //=========================//

        private function doMoveScrollPanelXDirection(_moveOffset:int):int
        {
            if (mIsLockInView) {
                return GeneralUtils.normalizingValue(mScrollPanel.viewportRect.x - _moveOffset, 0, mScrollPanel.maxMoveRect.width);
            } else {
                return mScrollPanel.viewportRect.x - _moveOffset;
            }
        }

        private function doMoveScrollPanelYDirection(_moveOffset:int):int
        {
            if (mIsLockInView) {
                return GeneralUtils.normalizingValue(mScrollPanel.viewportRect.y - _moveOffset, 0, mScrollPanel.maxMoveRect.height);
            } else {
                return mScrollPanel.viewportRect.y - _moveOffset;
            }
        }

        /**
         * 松手时候 根据整个共移动的距离 及Touch的时间 计算出ScrollPanel应该滑动到的位置
         */
        private function calculateCancelScrollToPositionX(_moveOffsetX:Number, _touchDuringTime:int):int
        {
            var position:int;
            if (mScrollPanel.viewportRect.x < 0) {
                position = 0;
            }
            else if (mScrollPanel.viewportRect.x > mScrollPanel.maxMoveRect.width) {
                position = mScrollPanel.maxMoveRect.width;
            }
            else {
                var slideSizeX:int = _touchDuringTime <= TOUCH_CONFIRM_SCROLL_TIME ? _moveOffsetX / _touchDuringTime * mScrollPanel.viewportRect.width : 0;
                position = GeneralUtils.normalizingValue(mScrollPanel.viewportRect.x - slideSizeX, 0, mScrollPanel.maxMoveRect.width);
            }
            return position;
        }

        /**
         * 松手时候 根据整个共移动的距离 及Touch的时间 计算出ScrollPanel应该滑动到的位置
         */
        private function calculateCancelScrollToPositionY(_moveOffsetY:Number, _touchDuringTime:int):int
        {
            var position:int;
            if (mScrollPanel.viewportRect.y < 0) {
                position = 0;
            }
            else if (mScrollPanel.viewportRect.y > mScrollPanel.maxMoveRect.height) {
                position = mScrollPanel.maxMoveRect.height;
            }
            else {
                var slideSizeY:int = _touchDuringTime <= TOUCH_CONFIRM_SCROLL_TIME ? _moveOffsetY / _touchDuringTime * mScrollPanel.viewportRect.height : 0;
                position = GeneralUtils.normalizingValue(mScrollPanel.viewportRect.y - slideSizeY, 0, mScrollPanel.maxMoveRect.height);
            }
            return position;
        }


    }
}
